﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using SimpleIR;

using System.Xml;

namespace PInfoModel
{
	/// <summary>
	/// This class provides a wrapper for easy desirailization of PIModel information.
	/// </summary>
	internal abstract class PInfoDeSerializer
	{
		internal readonly Dictionary<int, IRType> TypeMap;

		internal readonly Dictionary<int, IRMemberField> FieldMap;

		internal readonly Dictionary<int, IRBasicAccessPath> PathMap;

		internal readonly Dictionary<int, IRRootIdentifier> RootMap;

		internal readonly Dictionary<int, string> StringMap;

		protected PInfoDeSerializer(Dictionary<IRType, int> tmap, Dictionary<IRMemberField, int> fmap, Dictionary<IRBasicAccessPath, int> pmap, Dictionary<IRRootIdentifier, int> rmap, Dictionary<string, int> smap)
		{
			this.TypeMap = new Dictionary<int, IRType>();
			foreach(KeyValuePair<IRType, int> tm in tmap)
				this.TypeMap.Add(tm.Value, tm.Key);

			this.FieldMap = new Dictionary<int, IRMemberField>();
			foreach(KeyValuePair<IRMemberField, int> fm in fmap)
				this.FieldMap.Add(fm.Value, fm.Key);

			this.PathMap = new Dictionary<int, IRBasicAccessPath>();
			foreach(KeyValuePair<IRBasicAccessPath, int> pm in pmap)
				this.PathMap.Add(pm.Value, pm.Key);

			this.RootMap = new Dictionary<int, IRRootIdentifier>();
			foreach(KeyValuePair<IRRootIdentifier, int> rm in rmap)
				this.RootMap.Add(rm.Value, rm.Key);

			this.StringMap = new Dictionary<int, string>();
			foreach(KeyValuePair<string, int> rm in smap)
				this.StringMap.Add(rm.Value, rm.Key);
		}

		internal abstract void SetDeserializationStream(object dsr);

		internal IRType ReadIRType(string ttag)
		{
			int tid = this.ReadInt(ttag);
			return this.TypeMap[tid];
		}

		internal IRMemberField ReadIRField(string ftag)
		{
			int fid = this.ReadInt(ftag);
			return this.FieldMap[fid];
		}

		internal IRBasicAccessPath ReadIRBasicAccessPath(string ptag)
		{
			int pid = this.ReadInt(ptag);
			return this.PathMap[pid];
		}

		internal IRRootIdentifier ReadIRRoot(string rtag)
		{
			int rid = this.ReadInt(rtag);
			return this.RootMap[rid];
		}

		internal string ResolveString(int stag)
		{
			return this.StringMap[stag];
		}

		internal abstract void ReadStartTag(string tag);

		internal abstract void ReadEndTag(string tag);

		internal abstract int ReadCollectionStartTag(string lname);

		internal abstract void ReadCollectionEndTag(string lname);

		internal abstract bool ReadBool(string name);

		internal abstract int ReadInt(string name);

		internal abstract string ReadString(string name);
	}

	/// <summary>
	/// This class provides a wrapper for easy desirailization of PIModel information in a XML format.
	/// </summary>
	internal sealed class PInfoDeSerializerXML : PInfoDeSerializer
	{
		private XmlReader m_xr;

		private Stack<Tuple<string, bool>> m_state;

		internal PInfoDeSerializerXML(Dictionary<IRType, int> tmap, Dictionary<IRMemberField, int> fmap, Dictionary<IRBasicAccessPath, int> pmap, Dictionary<IRRootIdentifier, int> rmap, Dictionary<string, int> smap)
			: base(tmap, fmap, pmap, rmap, smap)
		{ this.m_state = new Stack<Tuple<string, bool>>(); }

		internal override void SetDeserializationStream(object dsr)
		{ this.m_xr = (XmlReader)dsr; }

		internal override void ReadStartTag(string tag)
		{
			if(this.m_state.Count != 0)
			{
				if(this.m_state.Peek().Item2)
				{
					this.m_xr.ReadStartElement(this.m_state.Peek().Item1);
					Tuple<string, bool> spp = this.m_state.Pop();
					this.m_state.Push(new Tuple<string, bool>(spp.Item1, false));
				}
			}

			this.m_state.Push(new Tuple<string, bool>(tag, true));
		}

		internal override void ReadEndTag(string tag)
		{
			Contract.Assert(this.m_state.Count != 0 && this.m_state.Peek().Item1.Equals(tag));

			if(this.m_xr.IsEmptyElement)
				this.m_xr.ReadStartElement(tag);
			else
				this.m_xr.ReadEndElement();

			this.m_state.Pop();
		}

		internal override int ReadCollectionStartTag(string lname)
		{
			this.ReadStartTag(lname);
			return Int32.Parse(this.m_xr.GetAttribute("num"));
		}

		internal override void ReadCollectionEndTag(string lname)
		{ this.ReadEndTag(lname); }

		internal override bool ReadBool(string name)
		{ return Boolean.Parse(this.m_xr.GetAttribute(name)); }

		internal override int ReadInt(string name)
		{ return Int32.Parse(this.m_xr.GetAttribute(name)); }

		internal override string ReadString(string name)
		{ return this.m_xr.GetAttribute(name); }
	}

	/// <summary>
	/// This class provides a wrapper for easy desirailization of PIModel information in a Binary format.
	/// </summary>
	internal sealed class PInfoDeSerializerBinary : PInfoDeSerializer
	{
		private System.IO.BinaryReader m_br;

		internal PInfoDeSerializerBinary(Dictionary<IRType, int> tmap, Dictionary<IRMemberField, int> fmap, Dictionary<IRBasicAccessPath, int> pmap, Dictionary<IRRootIdentifier, int> rmap, Dictionary<string, int> smap)
			: base(tmap, fmap, pmap, rmap, smap)
		{ ;}

		internal override void SetDeserializationStream(object dsr)
		{ this.m_br = (System.IO.BinaryReader)dsr; }

		internal override void ReadStartTag(string tag)
		{
			int rr = this.m_br.ReadInt32();

			Contract.Assert(this.StringMap.ContainsKey(rr) && this.StringMap[rr].Equals(tag));
		}

		internal override void ReadEndTag(string tag)
		{
			int rr = -this.m_br.ReadInt32();

			Contract.Assert(this.StringMap.ContainsKey(rr) && this.StringMap[rr].Equals(tag));
		}

		internal override int ReadCollectionStartTag(string lname)
		{
			this.ReadStartTag(lname);
			return this.m_br.ReadInt32();
		}

		internal override void ReadCollectionEndTag(string lname)
		{ this.ReadEndTag(lname); }

		internal override bool ReadBool(string name)
		{ return this.m_br.ReadInt32() == 1; }

		internal override int ReadInt(string name)
		{ return this.m_br.ReadInt32(); }

		internal override string ReadString(string name)
		{
			int rr = this.m_br.ReadInt32();
			return this.StringMap[rr];
		}
	}
}
